using System;
using System.IO.Ports;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Diagnostics;
using System.Security.Cryptography;
using Force.Crc32;
namespace SerialCommunication
{
    /// <summary>
    /// RS232串口通信类，支持大数据分包传输、校验、重发机制以及异步操作
    /// </summary>
    public class SerialCommunicator : IDisposable
    {
        // 串口相关字段
        public readonly SerialPort _serialPort;
        private readonly object _lockObject = new object();
        private bool _isDisposed = false;

        // 数据包相关常量
        private const byte ACK = 0x06;  // 确认字符
        private const byte NAK = 0x15;  // 否定字符
        private const int HeaderSize = 7;  // 包头大小：同步字节(2) + 包ID(2) +总包数(2)+ 包大小(1)

        // 配置参数
        private readonly int _maxPacketSize;
        private readonly int _timeoutMs;
        private readonly int _maxRetries;

        // 接收缓冲区
        private readonly Dictionary<ushort, byte[]> _receivedPackets = new Dictionary<ushort, byte[]>();
        private readonly List<byte> _receiveBuffer = new List<byte>();

        // 异步操作相关
        private readonly SemaphoreSlim _sendSemaphore = new SemaphoreSlim(1, 1);
        private CancellationTokenSource _receiveCts = new CancellationTokenSource();

        // 事件
        public event EventHandler<DataReceivedEventArgs> DataReceived;
        public event EventHandler<ErrorEventArgs> ErrorOccurred;
        public event EventHandler<ProcessEventArgs> ProcessOccurred;
        public event EventHandler<ProcessEventArgs> AcceptProcessOccurred;

        /// <summary>
        /// 初始化SerialCommunicator类的新实例
        /// </summary>
        /// <param name="portName">串口号，如COM1</param>
        /// <param name="baudRate">波特率</param>
        /// <param name="maxPacketSize">每个数据包的最大大小（不包括头部）</param>
        /// <param name="timeoutMs">超时时间（毫秒）</param>
        /// <param name="maxRetries">最大重试次数</param>
        public SerialCommunicator(string portName, int baudRate = 9600, int maxPacketSize = 128,
            int timeoutMs = 20000, int maxRetries = 3)
        {
            _maxPacketSize = maxPacketSize;
            _timeoutMs = timeoutMs;
            _maxRetries = maxRetries;

            // 初始化串口
            _serialPort = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One);
        }

        /// <summary>
        /// 异步打开串口连接
        /// </summary>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>表示异步操作的任务</returns>
        public async Task OpenAsync(CancellationToken cancellationToken = default)
        {
            if (_isDisposed)
                throw new ObjectDisposedException(nameof(SerialCommunicator));

            if (!_serialPort.IsOpen)
            {
                await Task.Run(() => _serialPort.Open(), cancellationToken);

                // 启动异步接收任务
                _receiveCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
                Task.Run(() => ReceiveDataAsync(_receiveCts.Token), _receiveCts.Token);
            }
        }

        /// <summary>
        /// 异步关闭串口连接
        /// </summary>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>表示异步操作的任务</returns>
        public async Task CloseAsync(CancellationToken cancellationToken = default)
        {
            if (_isDisposed)
                return;

            _receiveCts.Cancel();

            if (_serialPort.IsOpen)
            {
                await Task.Run(() => _serialPort.Close(), cancellationToken);
            }
        }

        /// <summary>
        /// 异步发送大数据，自动分包
        /// </summary>
        /// <param name="data">要发送的数据</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>表示异步操作的任务，包含发送结果</returns>
        public async Task<bool> SendDataAsync(byte[] data, CancellationToken cancellationToken = default)
        {
            if (_isDisposed)
                throw new ObjectDisposedException(nameof(SerialCommunicator));

            if (data == null || data.Length == 0)
                return false;

            await _sendSemaphore.WaitAsync(cancellationToken);

            try
            {
                // 计算需要分成多少个包
                int packetCount = (int)Math.Ceiling((double)data.Length / _maxPacketSize);

                for (ushort packetId = 0; packetId < packetCount; packetId++)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    int offset = packetId * _maxPacketSize;
                    int length = Math.Min(_maxPacketSize, data.Length - offset);

                    byte[] packetData = new byte[length];
                    Array.Copy(data, offset, packetData, 0, length);
                    Trace.WriteLine($"发送包号:{packetId}");
                    var b = await SendPacketAsync(packetId, (ushort)packetCount, packetData, cancellationToken);

                    if (!b)
                    {
                        Trace.WriteLine($"发送包号:{packetId} 失败!");
                        OnErrorOccurred(new ErrorEventArgs($"Packet {packetId} send failed after {_maxRetries} retries"));
                        return false;
                    }
                    var processStr = $"进度:下发完成 {packetId+1} 个包 / 共 {packetCount} 个包";
                    OnProcessOccurred(new ProcessEventArgs(processStr));
                }

                return true;
            }
            catch(Exception e)
            {
                Trace.WriteLine(e.ToString());
                return false;
            }
            finally
            {
                _sendSemaphore.Release();
            }
        }

        /// <summary>
        /// 异步发送单个数据包，包含重试机制
        /// </summary>
        private async Task<bool> SendPacketAsync(ushort packetId,ushort packetCount, byte[] data, CancellationToken cancellationToken)
        {
            byte[] packet = BuildPacket(packetId, packetCount, data);
            int retryCount = 0;
            TaskCompletionSource<bool> ackReceived = new TaskCompletionSource<bool>();
            bool packetAcked = false;

            // 注册ACK/NAK处理事件
            EventHandler<DataReceivedEventArgs> handler = (sender, e) =>
            {
                if (e.Data.Length == 1)
                {
                    if (e.Data[0] == ACK)
                    {
                        Trace.WriteLine($"接收到回复成功 {ACK}");
                        packetAcked = true;
                        ackReceived.TrySetResult(true);
                    }
                    else if (e.Data[0] == NAK)
                    {
                        Trace.WriteLine($"接收到回复失败 {NAK}");
                        ackReceived.TrySetResult(false);
                    }
                }
            };

            DataReceived += handler;

            try
            {
                using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

                while (retryCount < _maxRetries && !packetAcked && !cancellationToken.IsCancellationRequested)
                {
                    timeoutCts.CancelAfter(_timeoutMs);

                    try
                    {
                        Trace.WriteLine($"length:{packet.Length}=>{BitConverter.ToString(packet)}");
                        // 发送数据包
                        await WriteAsync(packet, 0, packet.Length, timeoutCts.Token);

                        // 等待ACK
                        var completedTask = await Task.WhenAny(ackReceived.Task, Task.Delay(Timeout.Infinite, timeoutCts.Token));

                        if (completedTask == ackReceived.Task)
                        {
                            bool result = await ackReceived.Task;

                            if (!result)
                            {
                                // 收到NAK，需要重发
                                retryCount++;
                                ackReceived = new TaskCompletionSource<bool>();
                            }
                        }
                        else
                        {
                            // 超时
                            throw new OperationCanceledException();
                        }

                    }
                    catch (OperationCanceledException)
                    {
                        if (cancellationToken.IsCancellationRequested)
                            throw;

                        // 超时，需要重发
                        retryCount++;
                        ackReceived = new TaskCompletionSource<bool>();
                    }
                }

                return packetAcked;
            }
            finally
            {
                DataReceived -= handler;
            }
        }

        /// <summary>
        /// 构建数据包（添加头部和校验）
        /// </summary>
        private byte[] BuildPacket(ushort packetId,ushort packetCount, byte[] data)
        {
            byte[] packet = new byte[HeaderSize + 2 + data.Length + 2];

            // 同步字节
            packet[0] = 0xAA;
            packet[1] = 0x55;
           
            // 包ID（2字节，小端序）
            WriteUInt16LittleEndian(packet, 2, packetId);

            // 总包数（2字节，小端序）
            WriteUInt16LittleEndian(packet, 4, packetCount);

            // 包大小
            packet[6] = (byte)data.Length;

            // 数据
            Array.Copy(data, 0, packet, HeaderSize, data.Length);

            // 计算并添加CRC校验
            ushort crc = CalculateCRC(data);
            string crcstr = String.Format("{0:X}", crc);
            Trace.WriteLine(crcstr);
            WriteUInt16LittleEndian(packet, packet.Length - 2, crc);

            return packet;
        }

        /// <summary>
        /// 以小端序写入UInt16
        /// </summary>
        private static void WriteUInt16LittleEndian(byte[] buffer, int offset, ushort value)
        {
            buffer[offset] = (byte)value;
            buffer[offset + 1] = (byte)(value >> 8);
        }

        /// <summary>
        /// 以小端序读取UInt16
        /// </summary>
        private static ushort ReadUInt16LittleEndian(byte[] buffer, int offset)
        {
            return (ushort)(buffer[offset] | (buffer[offset + 1] << 8));
        }

        /// <summary>
        /// 异步接收数据
        /// </summary>
        private async Task ReceiveDataAsync(CancellationToken cancellationToken)
        {
            try
            {
                byte[] buffer = new byte[4096];

                while (!cancellationToken.IsCancellationRequested)
                {
                    int bytesRead = 0;
                 
                       
                            // 关键改进：检查缓冲区中可用的字节数
                            int bytesAvailable = _serialPort.BytesToRead;

                            if (bytesAvailable > 0)
                            {
                                // 动态调整缓冲区大小，避免读取过多或过少
                                int bufferSize = Math.Min(bytesAvailable, 4096);
                                buffer = new byte[bufferSize];

                                bytesRead = await _serialPort.BaseStream.ReadAsync(buffer, 0, buffer.Length, cancellationToken);
                            }
                        
                                        
                                                  
                    
                    if (bytesRead > 0 )
                    {
                        //如果是确认的,打印状态
                        if (buffer[0]==ACK  || buffer[0] == NAK)
                        {
                            byte[] assembledData = new byte[1];
                            assembledData[0] = buffer[0];                          
                            OnDataReceived(new DataReceivedEventArgs(assembledData));
                            continue;
                        }
                        byte[] receivedData = new byte[bytesRead];
                        Array.Copy(buffer, receivedData, bytesRead);

                        // 调试输出接收到的数据
                        Trace.WriteLine($"收到 {bytesRead} 字节数据: {BitConverter.ToString(receivedData)}");

                        ProcessReceivedData(receivedData);
                    }
                }
            }
            catch (OperationCanceledException)
            {
                // 正常取消，忽略
            }
            catch (Exception ex)
            {
                if (!cancellationToken.IsCancellationRequested)
                {
                    OnErrorOccurred(new ErrorEventArgs($"Data receiving error: {ex.Message}"));
                }
            }
        }

        /// <summary>
        /// 处理接收到的数据
        /// </summary>
        private void ProcessReceivedData(byte[] data)
        {
            lock (_lockObject)
            {
                _receiveBuffer.AddRange(data);
                ProcessBuffer();
            }
        }

        /// <summary>
        /// 处理接收缓冲区中的数据
        /// </summary>
        private void ProcessBuffer()
        {
            // 至少需要一个完整的头部大小才能开始处理
            while (_receiveBuffer.Count >= HeaderSize)
            {
                // 查找同步字节
                int syncIndex = _receiveBuffer.IndexOf(0xAA);
                if (syncIndex == -1 || syncIndex + 1 >= _receiveBuffer.Count || _receiveBuffer[syncIndex + 1] != 0x55)
                {
                    // 没有找到有效的同步字节，丢弃第一个字节
                    _receiveBuffer.RemoveAt(0);
                    continue;
                }

                // 检查数据包是否完整
                if (syncIndex + HeaderSize >= _receiveBuffer.Count)
                    break;

                // 获取包大小
                int dataSize = _receiveBuffer[syncIndex + 6];
                int packetSize = HeaderSize + dataSize + 4; // 头部 + 一共多少包 + 数据 + CRC

                // 检查整个数据包是否在缓冲区中
                if (syncIndex + packetSize > _receiveBuffer.Count)
                    break;

                // 提取数据包
                byte[] packet = _receiveBuffer.GetRange(syncIndex, packetSize).ToArray();

                // 移除已处理的数据
                _receiveBuffer.RemoveRange(0, syncIndex + packetSize);

                // 处理数据包
                ProcessPacket(packet);
            }
        }

        /// <summary>
        /// 处理单个数据包
        /// </summary>
        private void ProcessPacket(byte[] packet)
        {
            // 提取包ID
            ushort packetId = ReadUInt16LittleEndian(packet, 2);
            // 提取一共有多少个包
            ushort packetCount = ReadUInt16LittleEndian(packet, 4);

            // 提取数据
            int dataSize = packet[6];
            byte[] data = new byte[dataSize];
            Array.Copy(packet, HeaderSize, data, 0, dataSize);

            // 提取CRC
            ushort receivedCrc = ReadUInt16LittleEndian(packet, packet.Length - 2);

            // 计算CRC (只计算数据部分)
            ushort calculatedCrc = CalculateCRC(data);

            Trace.WriteLine($"处理包 {packetId}, 数据大小: {dataSize},共{packetCount}个包 ,接收CRC: 0x{receivedCrc:X4}, 计算CRC: 0x{calculatedCrc:X4}");

            // 校验CRC
           if (receivedCrc == calculatedCrc)
          // if(true)
            {
                Trace.WriteLine($"包 {packetId} CRC校验通过");

                // CRC校验通过，发送ACK
                SendAck(packetId, true);

                // 保存数据包
                _receivedPackets[packetId] = data;

                // 检查是否所有数据包都已接收
                CheckAndAssembleData(packetCount);
            }
            else
            {
                Trace.WriteLine($"包 {packetId} CRC校验失败!");

                // CRC校验失败，发送NAK
                SendAck(packetId, false);
            }
        }

        /// <summary>
        /// 发送确认消息(ACK/NAK)
        /// </summary>
        private void SendAck(ushort packetId, bool isAck)
        {
            byte[] ack = new byte[1];
            ack[0] = isAck ? ACK : NAK;

            Trace.WriteLine($"发送 {(isAck ? "ACK" : "NAK")} 确认包 {packetId}");

            lock (_lockObject)
            {
                _serialPort.Write(ack, 0, ack.Length);
            }
        }

        /// <summary>
        /// 检查并组装完整数据
        /// </summary>
        private void CheckAndAssembleData(ushort packetCount)
        {
            if (_receivedPackets.Count == 0)
                return;

            if (_receivedPackets.Count < packetCount)
            {
                Trace.WriteLine($"已接收 {_receivedPackets.Count}/{packetCount} 个包");
                var acceptprocessStr = $"进度:已接收 {_receivedPackets.Count+1} 个包 / 共 {packetCount} 个包";
                OnAcceptProcessOccurred(new ProcessEventArgs(acceptprocessStr));
                return; // 还有包未收到
            }
            //确定最大包ID
            ushort maxPacketId = 0;
            foreach (ushort id in _receivedPackets.Keys)
            {
                if (id > maxPacketId)
                    maxPacketId = id;
            }


            //// 检查是否所有包都已接收
            //for (ushort i = 0; i <= maxPacketId; i++)
            //{
            //    if (!_receivedPackets.ContainsKey(i))
            //    {
            //        Console.WriteLine($"等待包 {i}, 已接收 {_receivedPackets.Count}/{maxPacketId + 1} 个包");
            //        return; // 还有包未收到
            //    }
            //}

            // 计算总数据长度
            int totalLength = 0;
            foreach (byte[] data in _receivedPackets.Values)
            {
                totalLength += data.Length;
            }

            // 组装数据
            byte[] assembledData = new byte[totalLength];
            int offset = 0;

            for (ushort i = 0; i <= maxPacketId; i++)
            {
                byte[] packetData = _receivedPackets[i];
                Array.Copy(packetData, 0, assembledData, offset, packetData.Length);
                offset += packetData.Length;
            }

            Trace.WriteLine($"成功组装完整数据，大小: {assembledData.Length} 字节");

            // 触发数据接收事件
            OnDataReceived(new DataReceivedEventArgs(assembledData));

            // 清空接收缓冲区
            _receivedPackets.Clear();
        }

        /// <summary>
        /// 计算CRC校验值
        /// </summary>
        private ushort CalculateCRC(byte[] data)
        {
            //const ushort polynomial = 0xA001;
            //ushort crc = 0xFFFF;

            //for (int i = 0; i < data.Length; i++)
            //{
            //    crc ^= data[i];

            //    for (int j = 0; j < 8; j++)
            //    {
            //        if ((crc & 0x0001) != 0)
            //        {
            //            crc = (ushort)((crc >> 1) ^ polynomial);
            //        }
            //        else
            //        {
            //            crc >>= 1;
            //        }
            //    }
            //}
          ushort crc= (ushort)CalculateCRC32(data);
            return crc;
        }
        public static uint CalculateCRC32(byte[] data)
        {
            return Crc32Algorithm.Compute(data);
        }
        /// <summary>
        /// 异步写入数据到串口
        /// </summary>
        private async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        {
            await _serialPort.BaseStream.WriteAsync(buffer, offset, count, cancellationToken);
            await _serialPort.BaseStream.FlushAsync(cancellationToken);
        }

        /// <summary>
        /// 触发数据接收事件
        /// </summary>
        protected virtual void OnDataReceived(DataReceivedEventArgs e)
        {
            DataReceived?.Invoke(this, e);
        }

        /// <summary>
        /// 触发错误事件
        /// </summary>
        protected virtual void OnErrorOccurred(ErrorEventArgs e)
        {
            ErrorOccurred?.Invoke(this, e);
        }
        protected virtual void OnProcessOccurred(ProcessEventArgs e)
        {
            ProcessOccurred?.Invoke(this, e);
        }
        protected virtual void OnAcceptProcessOccurred(ProcessEventArgs e)
        {
            AcceptProcessOccurred?.Invoke(this, e);
        }
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// 释放资源的实现
        /// </summary>
        protected virtual void Dispose(bool disposing)
        {
            if (!_isDisposed)
            {
                if (disposing)
                {
                    // 释放托管资源
                    _receiveCts.Cancel();
                    _receiveCts.Dispose();

                    if (_serialPort != null)
                    {
                        _serialPort.Dispose();
                    }

                    _sendSemaphore.Dispose();
                }

                // 释放非托管资源

                _isDisposed = true;
            }
        }
    }

    /// <summary>
    /// 数据接收事件参数
    /// </summary>
    public class DataReceivedEventArgs : EventArgs
    {
        public byte[] Data { get; }

        public DataReceivedEventArgs(byte[] data)
        {
            Data = data;
        }
    }

    /// <summary>
    /// 错误事件参数
    /// </summary>
    public class ErrorEventArgs : EventArgs
    {
        public string ErrorMessage { get; }
        public string ProcessMessage { get; }

        public ErrorEventArgs(string errorMessage)
        {
            ErrorMessage = errorMessage;
        }
     
    }
    public class ProcessEventArgs : EventArgs
    {
        
        public string ProcessMessage { get; }
       
        public ProcessEventArgs(string processMessage)
        {
            ProcessMessage = processMessage;
        }
    }
}